﻿using MongoDB.Driver;
using MongoDB.Driver.Linq;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Linq.Expressions;

namespace MongdbHelper
{
    public class MongoDBHelper
    {
        private static readonly string connStr = ConfigurationManager.AppSettings["mongoConnStr"];//要连接到副本集，并自动发现主服务器，需要提供成员的种子列表
        private static readonly string dbName = ConfigurationManager.AppSettings["mongoDbName"];
        private IMongoDatabase dbBase = null;
        public IMongoClient client = null;
        private static string _connectionname { get; set; }

        public MongoDBHelper(string connectionname = null)
        {
            _connectionname = connectionname;
            //获取client
            client = GetClient();
            //获取连接库
            dbBase = client.GetDatabase(dbName);
        }
        public MongoDBHelper(string url, string dbname, string connectionname = null)
        {
            _connectionname = connectionname;
            //获取client
            client = GetClient(url);
            //获取连接库
            dbBase = client.GetDatabase(dbname);
        }
        public IMongoClient GetClient()
        {
            try
            {
                var client = new MongoClient(connStr);//首选从节点，大多情况下读操作在从节点，特殊情况（如单主节点架构）读操作在主节点。
                return client;
            }
            catch (Exception ex)
            {
                LoggerHelper.Log("Mongo-Insert", ex.Message);
            }
            return null;
        }
        public IMongoClient GetClient(string connStr)
        {
            try
            {
                var client = new MongoClient(connStr);//首选从节点，大多情况下读操作在从节点，特殊情况（如单主节点架构）读操作在主节点。
                return client;
            }
            catch (Exception ex)
            {
                LoggerHelper.Log("Mongo-Insert", ex.Message);
            }
            return null;
        }
        /// <summary>
        /// 获取表对象
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="collectionName">表名</param>
        /// <returns></returns>
        public IMongoCollection<T> GetCollection<T>()
        {
            return dbBase.GetCollection<T>(_connectionname ?? typeof(T).Name);
        }

        /// <summary>
        /// 新增单个
        /// </summary>
        /// <typeparam name="T">数据模型</typeparam>
        /// <param name="model">数据</param>
        /// <returns></returns>
        public Boolean Insert<T>(T model, IClientSessionHandle session = null) where T : class
        {
            try
            {
                IMongoCollection<T> collection = this.GetCollection<T>();
                if (session != null)//使用事务
                {
                    collection.InsertOne(session, model);
                }
                else
                {
                    collection.InsertOne(model);
                }
                return true;
            }
            catch (Exception ex)
            {
                LoggerHelper.Log("Mongo-Insert", ex.Message);
                return false;
            }
        }
        /// <summary>
        /// 批量新增
        /// </summary>
        /// <typeparam name="T">数据模型</typeparam>
        /// <param name="list">数据</param>
        /// <returns></returns>
        public Boolean InsertMany<T>(List<T> list, IClientSessionHandle session = null) where T : class
        {
            
            IMongoCollection<T> collection = this.GetCollection<T>();
            if (session != null)//使用事务
            {
                collection.InsertMany(session, list);

            }
            else
            {
                collection.InsertMany(list, new InsertManyOptions() { BypassDocumentValidation = true });
            }
            GC.Collect();
            return true;

        }
        public Boolean BulkWrite<T>(List<WriteModel<T>> list, IClientSessionHandle session = null) where T : class
        {

            IMongoCollection<T> collection = this.GetCollection<T>();
            collection.BulkWrite(list, new BulkWriteOptions() { IsOrdered = false });
            GC.Collect();
            return true;

        }

        /// <summary>
        /// 删除单个
        /// </summary>
        /// <typeparam name="T">数据模型</typeparam>
        /// <param name="filter">删除条件</param>
        /// <returns></returns>
        public int Delete<T>(FilterDefinition<T> filter, IClientSessionHandle session = null) where T : class
        {
            try
            {
                if (session != null)
                {
                    IMongoCollection<T> collection = this.GetCollection<T>();
                    return ParseHelper.Int32Parse(collection.DeleteOne(session, filter).DeletedCount);
                }
                else
                {
                    IMongoCollection<T> collection = this.GetCollection<T>();
                    return ParseHelper.Int32Parse(collection.DeleteOne(filter).DeletedCount);
                }
            }
            catch (Exception ex)
            {
                LoggerHelper.Log("Mongo-Delete", ex.Message);
                return 0;
            }
        }
        /// <summary>
        /// 批量删除
        /// </summary>
        /// <typeparam name="T">数据模型</typeparam>
        /// <param name="filter">删除条件</param>
        /// <returns></returns>
        public int DeleteMany<T>(FilterDefinition<T> filter, IClientSessionHandle session = null) where T : class
        {
            try
            {
                if (session != null)
                {
                    IMongoCollection<T> collection = this.GetCollection<T>();
                    return ParseHelper.Int32Parse(collection.DeleteMany(session, filter).DeletedCount);
                }
                else
                {
                    IMongoCollection<T> collection = this.GetCollection<T>();
                    return ParseHelper.Int32Parse(collection.DeleteMany(filter).DeletedCount);

                }
            }
            catch (Exception ex)
            {
                LoggerHelper.Log("Mongo-DeleteMany", ex.Message);
                return 0;
            }
        }
        /// <summary>
        /// 更新数据
        /// </summary>
        /// <param name="filter">查询条件</param>
        /// <param name="update">修改值</param>
        public Boolean Update<T>(Expression<Func<T, bool>> filter, UpdateDefinition<T> update, IClientSessionHandle session = null) where T : class
        {
            try
            {
                if (session != null)
                {
                    IMongoCollection<T> collection = this.GetCollection<T>();
                    collection.UpdateOne(session, filter, update);
                    return true;
                }
                else
                {
                    IMongoCollection<T> collection = this.GetCollection<T>();
                    collection.UpdateOne(filter, update);
                    return true;
                }
            }
            catch (Exception ex)
            {
                LoggerHelper.Log("Mongo-Update", ex.Message);
                return false;
            }

        }
        /// <summary>
        /// 获取单个数据(过滤器)
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="where">查询条件</param>
        /// <returns></returns>
        public T Get<T>(Expression<Func<T, bool>> where) where T : class
        {
            try
            {
                IMongoCollection<T> collection = this.GetCollection<T>();
                return collection.AsQueryable().FirstOrDefault(where);
            }
            catch (Exception ex)
            {
                LoggerHelper.Log("Mongo-Get", ex.Message);
                return null;
            }
        }
        /// <summary>
        /// 获取所有数据
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="where">查询条件</param>
        /// <param name="order">排序</param>
        /// <returns></returns>
        public IMongoQueryable<T> GetAll<T>(Expression<Func<T, bool>> where, Expression<Func<T, object>> order = null, string orderBy = "ASC") where T : class
        {
            try
            {
                IMongoCollection<T> collection = this.GetCollection<T>();
                var query = collection.AsQueryable(new AggregateOptions { AllowDiskUse = true });//AllowDiskUse：允许使用磁盘调度,解决mongodb类存限制问题
                if (where != null)
                    query = query.Where(where);
                else
                    query = query.Where(x => true);
                if (order != null)
                {
                    if (orderBy.ToUpper() == "DESC")//降序排序
                        query = query.OrderByDescending(order);
                    else //升序排序
                        query = query.OrderBy(order);
                }
                return query;
            }
            catch (Exception ex)
            {
                LoggerHelper.Log("Mongo-GetAll", ex.Message);
                return null;
            }

        }
        public IFindFluent<T, T> GetAll<T>(Expression<Func<T, bool>> where, int count) where T : class
        {
            try
            {
                IMongoCollection<T> collection = this.GetCollection<T>();
                var query = collection.AsQueryable(new AggregateOptions { AllowDiskUse = true }).Take(count);//AllowDiskUse：允许使用磁盘调度,解决mongodb类存限制问题
                var query2 = collection.Find<T>(x => true).Limit(count);
                return query2;
            }
            catch (Exception ex)
            {
                LoggerHelper.Log("Mongo-GetAll", ex.Message);
                return null;
            }

        }
        public IMongoQueryable<T> GetAll2<T>(Expression<Func<T, bool>> where, int count, Expression<Func<T, object>> order = null) where T : class
        {
            try
            {
                IMongoCollection<T> collection = this.GetCollection<T>();
                var query = collection.AsQueryable(new AggregateOptions { AllowDiskUse = true });//AllowDiskUse：允许使用磁盘调度,解决mongodb类存限制问题
                if (order != null)
                {
                    query = query.OrderBy(order);
                }
                query = query.Take(count);
                return query;
            }
            catch (Exception ex)
            {
                LoggerHelper.Log("Mongo-GetAll", ex.Message);
                return null;
            }

        }
        public IMongoQueryable<T> GetAll<T>(int count, Expression<Func<T, bool>> where, Expression<Func<T, object>> order = null, string orderBy = "ASC") where T : class
        {
            try
            {
                IMongoCollection<T> collection = this.GetCollection<T>();
                var query = collection.AsQueryable(new AggregateOptions { AllowDiskUse = true });//AllowDiskUse：允许使用磁盘调度,解决mongodb类存限制问题
                if (where != null)
                    query = query.Where(where);
                else
                    query = query.Where(x => true);
                if (order != null)
                {
                    if (orderBy.ToUpper() == "DESC")//降序排序
                        query = query.OrderByDescending(order);
                    else //升序排序
                        query = query.OrderBy(order);
                }
                return query.Take(count);
            }
            catch (Exception ex)
            {
                LoggerHelper.Log("Mongo-GetAll", ex.Message);
                return null;
            }

        }
        /// <summary>
        /// 获取分页数据
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="pageIndex">页码</param>
        /// <param name="pageSize">每页条数</param>
        /// <param name="where">查询条件</param>
        /// <param name="outTotalPage">返回总页码数</param>
        /// <param name="totalCount">返回数据总条数</param>
        /// <param name="order">排序</param>
        /// <returns></returns>
        public IMongoQueryable<T> GetPageList<T>(int pageIndex, int pageSize, out int outTotalPage, out int totalCount, Expression<Func<T, bool>> where
            , Expression<Func<T, object>> order, string orderBy = "ASC") where T : class
        {
            try
            {
                IMongoCollection<T> collection = this.GetCollection<T>();
                if (pageIndex < 1 || pageSize < 1) { pageIndex = 0; pageSize = 0; }
                if (order == null)
                {
                    throw new Exception("order参数不能为 Null 值");
                }
                var query = collection.AsQueryable(new AggregateOptions { AllowDiskUse = true });//AllowDiskUse：允许使用磁盘调度,解决mongodb类存限制问题
                if (where != null)
                    query = query.Where(where);
                else
                    query = query.Where(x => true);
                //获取数据总条数
                totalCount = query.Count();
                //总页数 =  (数据总条数 + 每页显示条数 - 1) / 每页显示条数
                if (pageIndex > 0 && pageSize > 0)
                    outTotalPage = (totalCount + pageSize - 1) / pageSize;
                else
                    outTotalPage = 1;

                if (orderBy.ToUpper() == "DESC")//降序排序
                    query = query.OrderByDescending(order);
                else //升序排序
                    query = query.OrderBy(order);
                //判断是否分页
                if (pageIndex > 0 && pageSize > 0)
                    query = query.Skip((pageIndex - 1) * pageSize).Take(pageSize);
                return query;
            }
            catch (Exception ex)
            {
                // LoggerHelper.Log("Mongo-GetPageList", ex.Message);
                outTotalPage = 0;
                totalCount = 0;
                return null;
            }

        }
        public List<T> GetPageListFind<T>(int pageIndex, int pageSize, out int outTotalPage, out int totalCount, Expression<Func<T, bool>> where
         , Expression<Func<T, object>> order, string orderBy = "ASC") where T : class
        {
            try
            {
                IMongoCollection<T> collection = this.GetCollection<T>();
                if (pageIndex < 1 || pageSize < 1) { pageIndex = 0; pageSize = 0; }
                if (order == null)
                {
                    throw new Exception("order参数不能为 Null 值");
                }
                var query = collection.Find(where);

                //获取数据总条数
                var query2 = collection.AsQueryable(new AggregateOptions { AllowDiskUse = true });
                totalCount = query2.Count();
                //总页数 =  (数据总条数 + 每页显示条数 - 1) / 每页显示条数
                if (pageIndex > 0 && pageSize > 0)
                    outTotalPage = (totalCount + pageSize - 1) / pageSize;
                else
                    outTotalPage = 1;

                if (orderBy.ToUpper() == "DESC")//降序排序
                    query = query.SortBy(order);
                else //升序排序
                    query = query.SortBy(order);
                //判断是否分页
                if (pageIndex > 0 && pageSize > 0)
                    query = query.Skip((pageIndex - 1) * pageSize).Limit(pageSize);
                return query.ToList() ?? new List<T>();
            }
            catch (Exception ex)
            {

                outTotalPage = 0;
                totalCount = 0;
                return null;
            }

        }



        public List<T> GetAllFind<T>(int count, Expression<Func<T, bool>> where, Expression<Func<T, object>> order = null, string orderBy = "ASC") where T : class
        {
            try
            {
                IMongoCollection<T> collection = this.GetCollection<T>();
                var query = collection.Find(where);
                if (order != null)
                {
                    query = query.SortBy(order);
                }
                query = query.Limit(count);
                return query.ToList() ?? new List<T>();
            }
            catch (Exception ex)
            {
                //ErrorLog.WriteLog("Mongo-GetAll", ex.Message);
                return null;
            }

        }

        /// <summary>
        /// 单个添加
        /// </summary>
        /// <typeparam name="TDocument"></typeparam>
        /// <param name="filter"></param>
        public void InsertOne<TDocument>(TDocument filter)
        {
            var collection = this.GetCollection<TDocument>();
            collection.InsertOne(filter);
        }

        /// <summary>
        /// 单个查找
        /// </summary>
        /// <typeparam name="TDocument"></typeparam>
        /// <param name="filter"></param>
        /// <returns></returns>
        public TDocument FindOne<TDocument>(Expression<Func<TDocument, bool>> filter)
        {
            var collection = this.GetCollection<TDocument>();
            return collection.Find(filter).FirstOrDefault();
        }
        /// <summary>
        /// 批量查找
        /// </summary>
        /// <typeparam name="TDocument"></typeparam>
        /// <param name="filter"></param>
        /// <param name="filter1"></param>
        /// <returns></returns>
        public List<TDocument> FindMany<TDocument>(Expression<Func<TDocument, bool>> filter, Func<TDocument, object> filter1)
        {
            var collection = this.GetCollection<TDocument>().AsQueryable();
            return collection.Where(filter).ToList().OrderByDescending(filter1).ToList();
        }
        /// <summary>
        /// 更新数据
        /// </summary>
        /// <typeparam name="TDocument"></typeparam>
        /// <param name="filter"></param>
        /// <param name="upfilter"></param>
        public void UpdateOne<TDocument>(Expression<Func<TDocument, bool>> filter, UpdateDefinition<TDocument> upfilter, IClientSessionHandle session = null)
        {
            if (session != null)
            {
                var collection = this.GetCollection<TDocument>();
                collection.UpdateOne(session, filter, upfilter);
            }
            else
            {
                var collection = this.GetCollection<TDocument>();
                collection.UpdateOne(filter, upfilter);
            }
        }
        /// <summary>
        /// 单个删除
        /// </summary>
        /// <typeparam name="TDocument"></typeparam>
        /// <param name="filter"></param>
        public int DeleteOne<TDocument>(Expression<Func<TDocument, bool>> filter)
        {
            var collection = this.GetCollection<TDocument>();
            var count = collection.DeleteOne<TDocument>(filter);
            return Convert.ToInt32(count.DeletedCount);
        }
        /// <summary>
        /// 批量删除
        /// </summary>
        /// <typeparam name="TDocument"></typeparam>
        /// <param name="filter"></param>
        public int DeleteMany<TDocument>(Expression<Func<TDocument, bool>> filter)
        {
            var collection = this.GetCollection<TDocument>();
            var count = collection.DeleteMany<TDocument>(filter);
            return Convert.ToInt32(count.DeletedCount);
        }



    }

}
